package morenoapp.action;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ActionMap;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import morenoapp.MorenoApp;
import morenoapp.MorenoMainView;
import morenoapp.components.about.AboutDialog;
import morenoapp.components.common.ExceptionDialog;
import morenoapp.components.workplace.WorkplaceNavigator;
import morenoapp.components.workplace.WorkplaceView;
import morenoapp.components.workplace.WorkspaceNavigatorListener;
import morenoapp.model.MorenoModelException;
import morenoapp.model.app.MorenoApplicationVetoException;
import morenoapp.model.data.MorenoModelBatchJob;
import morenoapp.model.data.MorenoModelData;
import morenoapp.model.data.MorenoModelFace;
import morenoapp.model.data.MorenoQuestionFace;
import morenoapp.model.enums.MorenoModelStage;
import morenoapp.model.enums.MorenoQuestionType;
import morenoapp.model.listeners.MorenoModelAdapter;
import morenoapp.util.DocumentedComponent;
import morenoapp.util.I18N;
import morenoapp.util.MorenoUtil;
import morenoapp.util.Order;
import morenoapp.util.ShouldNotHappenException;
import org.jdesktop.application.Action;

/**
 *
 * @author dmitry.mamonov
 */
public class MorenoActions {
    private static MorenoActions instance = null;
    private ActionMap actionMap = null;
    private MorenoModelFace model;
    private WorkplaceNavigator navigator;
    public static MorenoActions getInstance() {
        if (instance == null) {
            instance = new MorenoActions();
            instance.actionMap = MorenoApp.getApplication().getContext().getActionMap(instance);
        }
        return instance;
    }

    public javax.swing.Action getAction(final String name) {
        return new MorenoActionProxy(name, actionMap.get(name));
    }

    public void setupModel(MorenoModelFace _model){
        this.model = _model;
        model.addModelListener(new MorenoModelAdapter(){
            @Override
            public void onWholeModelChanged() {
                updateModelActions();
            }
        });
        updateModelActions();
    }

    public void setupWorkplaceNavigator(WorkplaceNavigator _navigator){
        this.navigator = _navigator;
        navigator.addNavigatorListener(new WorkspaceNavigatorListener() {
            @Override
            public void onSelectedView(WorkplaceView view) {
                updateNavigationActions(view);
            }
        });
        updateNavigationActions(navigator.getCurrentView());
    }

    private void updateModelActions(){
        boolean noModel = model.getStage()==MorenoModelStage.NO_MODEL;
        MorenoActionsFacade.getActionCreateNewModel().setEnabled(noModel==true);
        //MorenoActionsFacade.getActionImportResearch().setEnabled(noModel==true);
        MorenoActionsFacade.getActionOpenModel().setEnabled(noModel==true);

        MorenoActionsFacade.getActionSaveModel().setEnabled(noModel==false);
        MorenoActionsFacade.getActionSaveAsModel().setEnabled(noModel==false);
        MorenoActionsFacade.getActionCloseModel().setEnabled(noModel==false);
    }

    public void updateNavigationActions(WorkplaceView view){
        MorenoActionsFacade.getActionNavigateNext().setEnabled(view.next()!=null);
        MorenoActionsFacade.getActionNavigatePrev().setEnabled(view.prev()!=null);
    }

    @Action
    @Order(value = 10)
    public void actionCreateNewModel() {
        model.createModel();
        model.doBatchJob(new MorenoModelBatchJob() {
            @Override
            public void processModel(MorenoModelData model) {
                for (int i = 0; i < 10; i++) {
                    model.createRespondent();
                }

                MorenoQuestionFace quest;
                quest = model.createQuestion();
                quest.setContent(I18N.get("text.positive_question"));
                quest.setType(MorenoQuestionType.Positive);
                quest.setColor(Color.GREEN);
                quest.setMarker("+"); //NOI18N

                quest = model.createQuestion();
                quest.setContent(I18N.get("text.negative_question"));
                quest.setType(MorenoQuestionType.Negative);
                quest.setColor(Color.RED);
                quest.setMarker("--"); //NOI18N

                quest = model.createQuestion();
                quest.setContent(I18N.get("text.referential_question"));
                quest.setType(MorenoQuestionType.Referential);
                quest.setColor(Color.BLUE);
                quest.setMarker("R"); //NOI18N
            }

        });

        actionNavigateStartWork();
    }

    @Action
    @Order(value = 20)
    public void actionImportResearch() {
        throw new ShouldNotHappenException();
    }

    @Action
    @Order(value = 30)
    public void actionNavigateNext() {
        MorenoApp.getApplication().getMainView().getNavigator().activateNextView();
    }

    @Action
    @Order(value = 40)
    public void actionNavigatePrev() {
        MorenoApp.getApplication().getMainView().getNavigator().activatePrevView();
    }

    @Action
    @Order(value = 50)
    public void actionNavigateWelcome() {
        MorenoApp.getApplication().getMainView().getNavigator().activateView(WorkplaceView.WelcomeView);
    }

    @Action
    @Order(value = 60)
    public void actionNavigateStartWork() {
        MorenoApp.getApplication().getMainView().getNavigator().activateView(WorkplaceView.ResearchView);
    }

    @Action
    @Order(value = 70)
    public void actionShowAppHelp() {
        try {
            Desktop.getDesktop().browse(new File("doc/morena.htm").toURI());
        } catch (IOException ex) {
            throw new ShouldNotHappenException(ex);
        }
    }

    @Action
    @Order(value = 80)
    public void actionCallSupport() {
        if (Desktop.isDesktopSupported()) {
            try {
                try {
                    Desktop.getDesktop().mail(new URI(I18N.get("uri.mail_to_developers_team")));
                } catch (URISyntaxException ex) {
                    JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), I18N.get("wrong_email_address_url_to_call_support"));
                }
            } catch (IOException e) {
                JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), I18N.get("message.can_not_open_email_client"));
            }
        } else {
            JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), I18N.get("message.mail_messaging_not_supported_by_platform"));
        }
    }

    @Action
    @Order(value = 90)
    public void actionOpenModel() {
        JFileChooser jFileChooser = new JFileChooser();
        try {
            jFileChooser.setApproveButtonText(I18N.get("open_research")); //I18N
            jFileChooser.setMultiSelectionEnabled(false);
            File lastFile = MorenoApp.getApplicationData().
                    getLastModelFile();
            if (lastFile.isFile()) {
                jFileChooser.setSelectedFile(lastFile);
            } else {
                jFileChooser.setCurrentDirectory(lastFile);
            }

            if (JFileChooser.APPROVE_OPTION == jFileChooser.showOpenDialog(MorenoApp.getApplication().getMainFrame())) {
                MorenoApp.getApplicationData().
                        setLastModelFile(jFileChooser.getSelectedFile());
                MorenoApp.getApplicationData().
                        loadModel(jFileChooser.getSelectedFile());
            }
        } catch (MorenoModelException ex) {
            JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), ex.getMessage());
        }
    }

    @Action
    @Order(value = 100)
    public void actionSaveModel() {
        try {
            MorenoApp.getApplicationData().
                    trySaveModel();

            //Если модель до этого не сохранялась, нужно выбрать файл
            if (model.getStoreURI() == null) {
                actionSaveAsModel();
                return;
            }

            //Если модель сохранялась, но теперь указанный адрес не корректен,
            //нужно выбрать файл.
            File targetSaveFile;
            try {
                targetSaveFile = new File(MorenoApp.getModel().
                        getStoreURI());
            } catch (IllegalArgumentException ex) {
                actionSaveAsModel();
                return;
            }

            //Модель ранее сохранялась, сохраням изменения в том же файле.
            try {
                MorenoApp.getApplicationData().
                        saveModel(targetSaveFile);
            } catch (MorenoModelException ex) {
                JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), ex.getMessage());
            }
        } catch (MorenoApplicationVetoException ex) {
            Logger.getLogger(getClass().getName()).log(Level.INFO, null, ex);
            JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), ex.getMessage());
        }
    }

    @Action
    @Order(value = 110)
    public void actionSaveAsModel() {
        try {
            MorenoApp.getApplicationData().
                    trySaveModel();

            JFileChooser jFileChooser = new JFileChooser();
            jFileChooser.setApproveButtonText(I18N.get("saving_research")); //I18N
            jFileChooser.setMultiSelectionEnabled(false);
            File lastFile = MorenoApp.getApplicationData().
                    getLastModelFile();
            if (lastFile.isFile()) {
                jFileChooser.setSelectedFile(lastFile);
            } else {
                jFileChooser.setCurrentDirectory(lastFile);
            }

            if (JFileChooser.APPROVE_OPTION == jFileChooser.showOpenDialog(MorenoApp.getApplication().getMainFrame())) {
                MorenoApp.getApplicationData().
                        setLastModelFile(jFileChooser.getSelectedFile());
                try {
                    MorenoApp.getApplicationData().
                            saveModel(jFileChooser.getSelectedFile());
                } catch (MorenoModelException ex) {
                    JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), ex.getMessage());
                }
            }
        } catch (MorenoApplicationVetoException ex) {
            Logger.getLogger(getClass().getName()).
                    log(Level.INFO, null, ex);
            JOptionPane.showMessageDialog(MorenoApp.getApplication().getMainFrame(), ex.getMessage());
        }
    }

    @Action
    @Order(value = 120)
    public void actionCloseModel() {
        MorenoApp.getModel().closeModel();
        actionNavigateWelcome();
    }

    @Action
    @Order(value = 130)
    public void actionExitApp() {
        MorenoApp.getApplication().exit();
    }

    @Action
    @Order(value = 140)
    public void actionDummy() {
        throw new RuntimeException("Dummy");
    }

    @Action
    @Order(value = 150)
    public void actionAbout() {
        AboutDialog.showAbout();
    }

    @Action
    @Order(value = 160)
    public void actionSubmitIssue() {
        throw new RuntimeException();
    }

    @Action
    @Order(value = 170)
    public void actionDebugSavelAllComponentsAsImages() {
        try {
            MorenoUtil.renderComponents(MorenoApp.getApplication().getMainFrame(), null, new File("./screens/all"));
        } catch (IOException ex) {
            throw new MorenoActionException(ex);
        }
    }

    @Action
    @Order(value = 180)
    public void actionDebugSaveImportantComponentsAsImages() {
        try {
            MorenoUtil.renderComponents(MorenoApp.getApplication().getMainFrame(), DocumentedComponent.class, new File("./screens/documented"));
        } catch (IOException ex) {
            throw new MorenoActionException(ex);
        }
    }

    @Action
    @Order(value = 190)
    public void actionDebugMakeScreenshots() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    final Robot r = new Robot();
                    final List<WorkplaceView> queue = new ArrayList(Arrays.asList(WorkplaceView.values()));
                    MorenoActions.getInstance().actionNavigateStartWork();
                    MorenoActions.getInstance().actionNavigatePrev();
                    final Runnable run = new Runnable() {
                        @Override
                        public void run() {
                            if (queue.isEmpty() == false) {
                                try {
                                    WorkplaceView view = queue.remove(0);
                                    BufferedImage im = r.createScreenCapture(MorenoApp.getApplication().getMainFrame().getBounds());
                                    ImageIO.write(im, "png", new File("step-" + (view.ordinal() + 1) + ".png")); //NOI18N
                                } catch (IOException ex) {
                                    throw new MorenoActionException(ex);
                                }
                                MorenoActions.getInstance().actionNavigateNext();
                                SwingUtilities.invokeLater(this);
                            }
                        }

                    };
                    SwingUtilities.invokeLater(run);
                } catch (AWTException ex) {
                    throw new MorenoActionException(ex);
                }
            }
        });
    }

    @Action
    @Order(value = 200)
    public void actionSetUILanguageRussian() {
        throw new RuntimeException();
    }

    @Action
    @Order(value = 210)
    public void actionSetUILanguageEnglish() {
        throw new RuntimeException();
    }

    @Action
    @Order(value = 220)
    public void actionSwitchToWizardView() {
        MorenoApp.getApplication().getMainView().setWizardMode(true);
    }

    @Action
    @Order(value = 230)
    public void actionSwitchToTabbedView() {
        MorenoApp.getApplication().getMainView().setWizardMode(false);
    }


    @Action
    @Order(value = 240)
    public void actionToggleNetworkOption() {
        throw new ShouldNotHappenException();
    }

    @Action
    @Order(value = 250)
    public void actionToggleWizardMode() {
        MorenoMainView view = MorenoApp.getApplication().getMainView();
        view.setWizardMode(!view.isWizardMode());
    }
    
    @Action
    @Order(value = 260)
    public void actionDebugResetInstallID() {
        MorenoApp.getApplicationData().resetInstallID();
    }

    @Action
    @Order(value = 260)
    public void actionExceptionDialogHide() {
        ExceptionDialog.getInstance().setVisible(false);
    }


    @Action
    @Order(value = 260)
    public void actionExceptionDialogSubmit() {
        ExceptionDialog.getInstance().submit();
    }

    @Action
    @Order(value = 270)
    public void actionThrowException() {
        throw new RuntimeException("Dummy exception");
    }
}
